﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;

namespace VGS
{
    /// <summary>
    /// Players class. Contains a list of players. This class is enumerable.
    /// </summary>
    public class Players : IList<Player> {
        private List<Player> _players = new List<Player>();

        public Players() { }

        #region IList<>
        /// <summary>
        /// Searches the specified object and returns the zero-based index of the first
        /// occurance within the list.
        /// </summary>
        /// <param name="item">Player item to search for</param>
        /// <returns>Player item's index</returns>
        public int IndexOf(Player item)
        {
            return _players.IndexOf(item);
        }

        /// <summary>
        /// Inserts an item into the list at the specified index.
        /// </summary>
        /// <param name="index">Index to insert at</param>
        /// <param name="item">Item to insert</param>
        public void Insert(int index, Player item)
        {
            _players.Insert(index, item);
        }

        /// <summary>
        /// Gets or sets the item at the specified zero-based index.
        /// </summary>
        /// <param name="index">Zero-based index</param>
        /// <returns>The player at the specified index</returns>
        /// /// <exception cref="ArgumentOutOfRangeException">Index out of range</exception>
        public Player this[int index]
        {
            get
            {
                if (index < 0 || index >= _players.Count)
                    throw new ArgumentOutOfRangeException("index", "Index out of range");
                return _players[index];
            }
            set
            {
                if (index < 0 || index >= _players.Count)
                    throw new ArgumentOutOfRangeException("index", "Index out of range");
                _players[index] = value;
            }

        }

        /// <summary>
        /// Removes the item at the specified zero-based index.
        /// </summary>
        /// <param name="index">The zero-based index</param>
        /// <exception cref="ArgumentOutOfRangeException">Index out of range</exception>
        public void RemoveAt(int index)
        {
            if (index < 0 || index >= _players.Count)
                throw new ArgumentOutOfRangeException("index", "Index out of range");
            _players.RemoveAt(index);
        }
        #endregion

        #region ICollection<>
        /// <summary>
        /// Gets the total number of players.
        /// </summary>
        public int Count
        {
            get
            {
                return _players.Count;
            }
        }


        /// <summary>
        /// Removes all elements from the list.
        /// </summary>
        public void Clear()
        {
            _players.Clear();
        }

        /// <summary>
        /// Determines whether an element is in the list.
        /// </summary>
        /// <param name="item">Item to search for</param>
        /// <returns>true if the specified element is in the list, otherwise false</returns>
        public bool Contains(Player item)
        {
            return _players.Contains(item);
        }

        /// <summary>
        /// Copies the players list to the specified array, starting at arrayIndex.
        /// </summary>
        /// <param name="array">Array to copy to</param>
        /// <param name="arrayIndex">The source's start index</param>
        public void CopyTo(Player[] array, int arrayIndex)
        {
            try
            {
                _players.CopyTo(array, arrayIndex);
            }
            catch (Exception)
            {
                throw; // Rethrow same exception
            }
        }

        /// <summary>
        /// Add a new player
        /// </summary>
        /// <param name="item">Item to add</param>
        public void Add(Player item)
        {
            _players.Add(item);
        }

        /// <summary>
        /// Removes the first occurance of the specified object from the list.
        /// </summary>
        /// <param name="item">Item to be removed</param>
        /// <returns>true if an item was removed, otherwise false</returns>
        public bool Remove(Player item)
        {
            return _players.Remove(item);
        }

        /// <summary>
        /// Since the list isn't read only, false is hardcoded to be returned.
        /// </summary>
        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }
        #endregion

        #region IEnumerable<>
        /// <summary>
        /// Return the generic enumerator.
        /// </summary>
        /// <returns>The generic IEnumerator</returns>
        public IEnumerator<Player> GetEnumerator()
        {
            foreach (Player p in _players)
                yield return p;
        }
        #endregion

        #region IEnumerable
        /// <summary>
        /// Hide the non-generic implementation.
        /// </summary>
        /// <returns>The generic implementation</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Removes all players with the specified shirt
        /// </summary>
        /// <param name="shirt">The player's shirt</param>
        public void RemoveAll(Predicate<Player> match)
        {
            //_players.RemoveAll(delegate(Player p) { return p.Shirt == shirt; });
            //_players.RemoveAll(p => p.Shirt == shirt);
            _players.RemoveAll(match);
        }

        /// <summary>
        /// Checks whether a player with the same shirt number already exists
        /// </summary>
        /// <param name="nr">Player's shirt</param>
        /// <returns>true if a player with that shirt exists, otherwise false</returns>
        public bool Exists(Predicate<Player> match)
        {
            if (_players.Exists(match))
                return true;
            return false;
        }

        /// <summary>
        /// Returns a player based on its shirt number. 'null' is returned if none is found.
        /// </summary>
        /// <param name="shirt">Player's shirt number</param>
        /// <returns>Returns the player with the specified shirt number or null if none were found</returns>
        //public Player GetPlayerByShirt(string shirt)
        //{
        //    if (Exists(shirt))
        //        return _players.Find(delegate(Player p) { return p.Shirt == shirt; });
        //    return null;
        //}
        public Player this[string shirt]
        {
            get
            {
                if (Exists(p => p.Shirt == shirt))
                    return _players.Find(p => p.Shirt == shirt);
                return null;
            }
        }
        #endregion
    }
}
